/******************************************************************************
* This file is part of is32p218 platform,
* Copyright (c) 2009 HangZhou InfoStrong CO.,LTD. All rights reserved.
* This software may only be used under the terms of a valid, current,
* end user license from InfoStrong.
* Nothing else gives you the right to use this software.   
*
* Name:   sys_glb.c
* Desc:   System global C file
* Author: Jerry
* Date:   2009-10-28
* Note:   
* History:
*
******************************************************************************/
#include "os_api.h"
#include "sys_glb.h"
#include "host_if.h"
#include "afn_def.h"
#include "app_afn.h"
#include "drv_uart.h"
#include "sys_log.h"
#include "drv_utils.h"
#include "bld_ver.h"
#include "app_isdp.h"
#include "drv_sys.h"

typedef void (*RESET_ENTRY)( void );

isOS_FLG g_sys_flg;

isOS_MEM g_sys_mem;
isOS_MEM g_sys_mem16;
__align(4) 
isOS_U8 g_sys_mem_buff[MEM_SYS_BLK_SIZE*MEM_SYS_BLK_NUM];
__align(4) 
isOS_U8 g_sys_mem16_buff[MEM_SYS_BLK16_SIZE*MEM_SYS_BLK16_NUM];

#if SYS_MEM_CHECK_FLG
#define SYS_MEM_STAT_FREE	0
#define SYS_MEM_STAT_BUSY	1
typedef struct
{
	U32 m_mem_addr;
	U8 m_mem_stat;
}SYS_MEM_CHK_OBJ_T;
SYS_MEM_CHK_OBJ_T g_sys_mem_chk[MEM_SYS_BLK_NUM];
SYS_MEM_CHK_OBJ_T g_sys_mem16_chk[MEM_SYS_BLK16_NUM];
#endif

#pragma arm section rodata= "global_info"
extern U32 IMAGE_END;
const GLB_INFO_MAP_T c_glb_info __attribute__((at(FLASH_EXE_ADDR+GLB_INFO_OFFSET)))=
{
	GLB_INFO_MAGIC_ID,
	INFO_STR_CHIP_ID,
	INFO_BCD_SW_VER,
	__DATE__,				// Format: "Nov 10 2010"
	INFO_SW_BLD_VER,
	(U32 **)&IMAGE_END,
	INFO_BCD_HW_VER
};
#pragma arm section rodata


#if SYS_MEM_CHECK_FLG
/*
* Function Name:
*   sys_mem_chk_init
* Description:
*   System memory check ( must be called after memory pool created
* Parameters:
*   isOS_MEM* p_mem_pool:
*   SYS_MEM_CHK_OBJ_T *p_mem_chk_list:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2012-3-2   
* Note:
*    
*/
BOOL sys_mem_chk_init( isOS_MEM *p_mem_pool, SYS_MEM_CHK_OBJ_T *p_mem_chk_list )
{
	U32 mem_addr;
	U32 mem_num;

	if ( NULL==p_mem_pool || NULL==p_mem_chk_list )
	{
		return FALSE;
	}

	mem_num = p_mem_pool->num_blocks;

	mem_addr = (U32)p_mem_pool->start_addr;
	while ( mem_num-- )
	{
		p_mem_chk_list->m_mem_addr = mem_addr;
		p_mem_chk_list->m_mem_stat = SYS_MEM_STAT_FREE;
		mem_addr += p_mem_pool->block_size;
		p_mem_chk_list++;
	}

	return TRUE;
}

/*
* Function Name:
*   sys_mem_chk
* Description:
*   system memory check
* Parameters: 
*   isOS_MEM *p_mem_pool
*   SYS_MEM_CHK_OBJ_T *p_mem_chk_list
*   void* p_mem:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2012-3-2   
* Note:
*    
*/
SYS_MEM_CHK_OBJ_T *sys_mem_chk( isOS_MEM *p_mem_pool, \
								SYS_MEM_CHK_OBJ_T *p_mem_chk_list, void *p_mem )
{
	U32 mem_num;

	if ( NULL==p_mem_pool || NULL==p_mem_chk_list )
	{
		return FALSE;
	}

	mem_num = p_mem_pool->num_blocks;
	while (mem_num--)
	{
		if ( (U32)p_mem == p_mem_chk_list->m_mem_addr )
		{
			return p_mem_chk_list;
		}
		p_mem_chk_list++;
	}

	return NULL;
}
#endif	// end SYS_MEM_CHECK_FLG

/*
* Function Name:
*   sys_glb_init
* Description:
*   System global resource init
* Parameters:
* Returns:
* Author				Date 
*  Jerry				2009-10-27   
* Note:
*    
*/
void sys_glb_init( void )
{
	isOS_S32 ret;

	ret = isOS_MemCreate( &g_sys_mem, g_sys_mem_buff, MEM_SYS_BLK_NUM, MEM_SYS_BLK_SIZE );
	if ( ret!= pdPASS )
	{
		IS_ASSERT(0);
	}

	ret = isOS_MemCreate( &g_sys_mem16, g_sys_mem16_buff, MEM_SYS_BLK16_NUM, MEM_SYS_BLK16_SIZE );
	if ( ret!= pdPASS )
	{
		IS_ASSERT(0);
	}

#if SYS_MEM_CHECK_FLG
	sys_mem_chk_init( &g_sys_mem, g_sys_mem_chk );
	sys_mem_chk_init( &g_sys_mem16, g_sys_mem16_chk );
#endif // end SYS_MEM_CHECK_FLG
	ret = isOS_FlgCreate( &g_sys_flg, FLG_ATTR_MULTI, 0, "System Flg" );
	if ( ret != pdPASS )
	{
		IS_ASSERT(0);
	}
}

/*
* Function Name:
*   sys_malloc
* Description:
*   Memory malloc
* Parameters:
*   U16 size: size of malloc
* Returns:
*  	void*: NULL: failure
* 	       Other: Memory data pointer
* Author				Date 
*  Jerry				2010-3-25   
* Note:
*    
*/
void *sys_malloc( U16 size )
{
	void *p_mem = NULL;
	BOOL try_flg = TRUE;
#if SYS_MEM_CHECK_FLG
	U32 cpu_sr;
#endif

	if ( size>MEM_SYS_BLK_SIZE )
	{
		IS_ASSERT(0);
		return NULL;
	}

	while ( try_flg )
	{
		p_mem = NULL;
		try_flg = FALSE;
		if ( size <=MEM_SYS_BLK16_SIZE )
		{
		#if SYS_MEM_CHECK_FLG
			isOS_ENTER_CRITICAL( cpu_sr );
		#endif
			if(  pdPASS == isOS_MemMalloc( &g_sys_mem16, &p_mem,TM_POLLING ) )
			{
			#if SYS_MEM_CHECK_FLG
				{	
					SYS_MEM_CHK_OBJ_T *p_mem_chk;
					p_mem_chk = sys_mem_chk( &g_sys_mem16, g_sys_mem16_chk, p_mem );
					if ( NULL==p_mem_chk || SYS_MEM_STAT_BUSY==p_mem_chk->m_mem_stat )
					{	// This Memory is error, should be discarded
						isOS_EXIT_CRITICAL( cpu_sr );
						#ifdef LOG_FLG
							{
								U32 msg_data[2];
								msg_data[0] = (U32)g_sys_mem16.block_size;
								msg_data[1] = (U32)p_mem;
								sys_utils_log( LOG_SYS_MEM_MLC_ERR, msg_data, sizeof(msg_data) );
							}
						#endif
						try_flg = TRUE;
						continue;		// Malloc try again
					}
					else
					{
						p_mem_chk->m_mem_stat = SYS_MEM_STAT_BUSY;
						isOS_EXIT_CRITICAL( cpu_sr );
						return p_mem;
					}
				}
			#else
				return p_mem;
			#endif
			}
		}
	
	#if SYS_MEM_CHECK_FLG
		isOS_ENTER_CRITICAL( cpu_sr );
	#endif
		if(  pdPASS != isOS_MemMalloc( &g_sys_mem, &p_mem,TM_POLLING ) )
		{
		#if SYS_MEM_CHECK_FLG
			isOS_EXIT_CRITICAL( cpu_sr );
		#endif
	#ifdef LOG_FLG
			{		
				sys_utils_log( LOG_SYS_OS_MEM_EMPTY, &g_sys_mem.fblkcnt, sizeof(g_sys_mem.fblkcnt) );
			}
	#endif
			return NULL;
		}
		#if SYS_MEM_CHECK_FLG
		{
			SYS_MEM_CHK_OBJ_T *p_mem_chk;
			p_mem_chk = sys_mem_chk( &g_sys_mem, g_sys_mem_chk, p_mem );
			if ( NULL==p_mem_chk || SYS_MEM_STAT_BUSY==p_mem_chk->m_mem_stat )
			{	// This Memory is error, should be discarded
				isOS_EXIT_CRITICAL( cpu_sr );
			#ifdef LOG_FLG
				{
					U32 msg_data[2];
					msg_data[0] = (U32)g_sys_mem.block_size;
					msg_data[1] = (U32)p_mem;
					sys_utils_log( LOG_SYS_MEM_MLC_ERR, msg_data, sizeof(msg_data) );
				}
			#endif
				try_flg = TRUE;
				continue;		// Malloc try again
			}
			else
			{	// Malloc OK
				p_mem_chk->m_mem_stat = SYS_MEM_STAT_BUSY;
				isOS_EXIT_CRITICAL( cpu_sr );
				return p_mem;
			}
		}
		#else
			return p_mem;
		#endif
	}

	return p_mem;
}

/*
* Function Name:
*   sys_free
* Description:
*   Memory free
* Parameters:
*   void* p_mem: Memory pointer of free
* Returns:
*  	BOOL: TRUE: success
*  	      FALSE: failue
* Author				Date 
*  Jerry				2010-3-25   
* Note:
*    
*/
BOOL sys_free( void *p_mem )
{
	isOS_MEM *p_sys_mem = NULL;
#if SYS_MEM_CHECK_FLG
	U32 cpu_sr;
#endif
	U32 mem_start = (U32)g_sys_mem.start_addr;
	U32 mem16_start = (U32)g_sys_mem16.start_addr;

	if ( mem16_start>mem_start )
	{
		p_sys_mem = ((U32)p_mem>=mem16_start)?(&g_sys_mem16):&g_sys_mem;
	}
	else
	{
		p_sys_mem = ((U32)p_mem>=mem_start)?(&g_sys_mem):&g_sys_mem16;
	}

#if SYS_MEM_CHECK_FLG
	{
		SYS_MEM_CHK_OBJ_T *p_mem_chk_list;
		SYS_MEM_CHK_OBJ_T *p_mem_chk;

		isOS_ENTER_CRITICAL( cpu_sr );
		p_mem_chk_list = (p_sys_mem==&g_sys_mem)?(g_sys_mem_chk):g_sys_mem16_chk;
		p_mem_chk = sys_mem_chk( p_sys_mem, p_mem_chk_list, p_mem );
		if ( NULL==p_mem_chk || SYS_MEM_STAT_FREE==p_mem_chk->m_mem_stat )
		{	// This Memory is error, should be discarded
			isOS_EXIT_CRITICAL( cpu_sr );
		#ifdef LOG_FLG
			{
				U32 msg_data[2];
				msg_data[0] = (U32)p_sys_mem->block_size;
				msg_data[1] = (U32)p_mem;
				sys_utils_log( LOG_SYS_MEM_FRE_ERR, msg_data, sizeof(msg_data) );
			}
		#endif
			return FALSE;
		}
		p_mem_chk->m_mem_stat = SYS_MEM_STAT_FREE;
	}
#endif
	if ( isOS_MemFree( p_sys_mem, p_mem ) !=pdPASS )
	{
		#if SYS_MEM_CHECK_FLG
			isOS_EXIT_CRITICAL( cpu_sr );
		#endif
		IS_ASSERT(0);
		return FALSE;
	}
#if SYS_MEM_CHECK_FLG
	isOS_EXIT_CRITICAL( cpu_sr );
#endif
	return TRUE;
}

/*
* Function Name:
*   sys_mem_free_num
* Description:
*   System memory block free number
* Parameters:
* Returns:
*   U8:
* Author				Date 
*  Jerry				2010-3-25   
* Note:
*    
*/
U8 sys_mem_free_num( void )
{
	return g_sys_mem.fblkcnt;
}
/*
* Function Name:
*   sys_utils_log
* Description:
*   utils log tools
* Parameters: 
*   U8 log_id: log id 
*   void* p_log_data:
*   S32 log_len:
* Returns:
* Author				Date 
*  Jerry				2009-11-16   
* Note:
*    
*/
void sys_utils_log( U8 log_id, void *p_log, S32 log_len )
{
#ifdef LOG_FLG
#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
	U8 snd_len = 0;
	U16 checksum = 0;
	HostISDPLLHdr *p_isdp_hdr;

	p_isdp_hdr = (HostISDPLLHdr *)sys_malloc(HOST_IF_ISDP_MSG_LEN(log_len+1));

	if ( NULL==p_isdp_hdr )
	{
		IS_ASSERT(0);
		return;
	}
	if(log_len >LOG_MEM_SIZE)
	{
		log_len = LOG_MEM_SIZE;
	}

	// Send Start SYN char 
	p_isdp_hdr->m_syn = HOST_IF_ISDP_DWORD_SYN;
	snd_len += 4;
	p_isdp_hdr->m_ctrl = ISDP_CMD_LOG_MSG|ISDP_CMD_UP_FLG;
	snd_len++;

	log_len +=1;			// Add id
	p_isdp_hdr->m_len = log_len ;
	snd_len++;
	p_isdp_hdr->m_data[0] = log_id;
	snd_len++;
	if ( log_len>1&&p_log!=NULL )
	{
		isOS_memcpy( (U8*)&p_isdp_hdr->m_data[1], (U8*)p_log, log_len-1 );
		snd_len += (log_len-1);
	}
	// -- CRC16
	checksum = drv_utils_crc16( (U8*)p_isdp_hdr, log_len+HOST_IF_ISDP_DATA_LEN_OFFSET );
	p_isdp_hdr->m_data[log_len] = checksum&0xFF;
	p_isdp_hdr->m_data[log_len+1] = (checksum>>8)&0xFF;
	snd_len +=2;
	// End char
	p_isdp_hdr->m_data[log_len+2] = HOST_IF_ISDP_CHAR_END;
	snd_len++;

	drv_uart_send( (U8*)p_isdp_hdr, snd_len, TRUE );

	if (!sys_free( (U8*)p_isdp_hdr ))
	{
		IS_ASSERT(0);
	}

#endif
#endif
}

/*
* Function Name:
*   sys_utils_log
* Description:
*   utils log tools
* Parameters: 
*   U8 log_id: log id 
*   void* p_log_data:
*   S32 log_len:
* Returns:
* Author				Date 
*  Jerry				2009-11-16   
* Note:
*    
*/
void sys_utils_log2( U8 log_id, void *p_log, S32 log_len )
{
#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
	U8 snd_len = 0;
	U16 checksum = 0;
	HostISDPLLHdr *p_isdp_hdr;

	p_isdp_hdr = (HostISDPLLHdr *)sys_malloc(HOST_IF_ISDP_MSG_LEN(log_len+1));
	if ( NULL==p_isdp_hdr )
	{
		IS_ASSERT(0);
		return;
	}
	if(log_len >LOG_MEM_SIZE)
	{
		log_len = LOG_MEM_SIZE;
	}

	// Send Start SYN char 
	p_isdp_hdr->m_syn = HOST_IF_ISDP_DWORD_SYN;
	snd_len += 4;
	p_isdp_hdr->m_ctrl = ISDP_CMD_LOG_MSG|ISDP_CMD_UP_FLG;
	snd_len++;

	log_len +=1;			// Add id
	p_isdp_hdr->m_len = log_len ;
	snd_len++;
	p_isdp_hdr->m_data[0] = log_id;
	snd_len++;
	if ( log_len>1&&p_log!=NULL )
	{
		isOS_memcpy( (U8*)&p_isdp_hdr->m_data[1], (U8*)p_log, log_len-1 );
		snd_len += (log_len-1);
	}
	// -- CRC16
	checksum = drv_utils_crc16( (U8*)p_isdp_hdr, log_len+HOST_IF_ISDP_DATA_LEN_OFFSET );
	p_isdp_hdr->m_data[log_len] = checksum&0xFF;
	p_isdp_hdr->m_data[log_len+1] = (checksum>>8)&0xFF;
	snd_len +=2;
	// End char
	p_isdp_hdr->m_data[log_len+2] = HOST_IF_ISDP_CHAR_END;
	snd_len++;

	drv_uart_send2( (U8*)p_isdp_hdr, snd_len, TRUE );

	if (!sys_free( (U8*)p_isdp_hdr ))
	{
		IS_ASSERT(0);
	}

#endif
}


/*
* Function Name:
*   IS_ASSERT_debug
* Description:
*   Assert routine in debug mode
* Parameters:
*   BOOL assert_flg:
*   S8* p_file_name:
*   U32 line:
* Returns:
* Author				Date 
*  Jerry				2009-11-16   
* Note:
*    
*/
void IS_ASSERT_debug( BOOL assert_flg, S8 *p_file_name, U32 line )
{
	if (assert_flg)
	{
		return;
	}
#ifdef LOG_FLG
	sys_utils_log( LOG_SYS_ASSERT_FILE,	(U8*)p_file_name, isOS_strlen(p_file_name)+1 );
	sys_utils_log( LOG_SYS_ASSERT_LINE, (U8*)&line, sizeof(line) );
#endif
#if 0 // $$$$$$$$$$$$
	while(1)
	{
	}
#endif
}


/*
* Function Name:
*   IS_ASSERT_Execption
* Description:
*   ARM Exception ASSERT
* Parameters:
*   S8* p_except_name:
*   U32 name_len:
*   U32 lr:
* Returns:
*   :
* Author				Date 
*  Jerry				2011-11-29   
* Note:
*    
*/
#define __ITOA(x) (x<=9)?(x+'0'):(x+0x37)
void IS_ASSERT_Execption( U8 *p_except_name, U32 name_len, U32 lr_val )
{
	U8 line_msg[11];

	drv_uart_baud_set( UART_BAUD_2400 );
	sys_utils_log2( LOG_SYS_ASSERT_FILE,	(U8*)p_except_name,name_len );
#if 1
	line_msg[0] = '0';
	line_msg[1] = 'x';
	line_msg[2] = ((lr_val>>28)&0x000000F);
	line_msg[2] = __ITOA(line_msg[2]);
	line_msg[3] = ((lr_val>>24)&0x000000F);
	line_msg[3] = __ITOA(line_msg[3]);
	line_msg[4] = ((lr_val>>20)&0x000000F);
	line_msg[4] = __ITOA(line_msg[4]);
	line_msg[5] = ((lr_val>>16)&0x000000F);
	line_msg[5] = __ITOA(line_msg[5]);
	line_msg[6] = ((lr_val>>12)&0x000000F);
	line_msg[6] = __ITOA(line_msg[6]);
	line_msg[7] = ((lr_val>>8)&0x000000F);
	line_msg[7] = __ITOA(line_msg[7]);
	line_msg[8] = (lr_val>>4)&0x0000000F;
	line_msg[8] = __ITOA(line_msg[8]);
	line_msg[9] = (lr_val&0x000000F);
	line_msg[9] = __ITOA(line_msg[9]);
	line_msg[10] = 0x00;
#endif

	sys_utils_log2( LOG_SYS_ASSERT_LINE, (U8*)line_msg, sizeof(line_msg) );
	{
		U32 loop = 10000;
		while(loop--)
		{
		}
	}
	drv_uart_baud_set( UART_BAUD_1200 );
	sys_utils_log2( LOG_SYS_ASSERT_FILE,	(U8*)p_except_name, name_len );
	sys_utils_log2( LOG_SYS_ASSERT_LINE, (U8*)line_msg, sizeof(line_msg) );
}

/*
* Function Name:
*   Undef_Handler_ISR
* Description:
*   ARM Undef handler ISR
* Parameters:
*   U32 lr: lr value
* Returns:
*   :
* Author				Date 
*  Jerry				2011-11-29   
* Note:
*    
*/
void Undef_Handler_ISR( U32 lr )
{
#ifdef SYS_DEBUG_FLG
	IS_ASSERT_Execption( (U8*)"Undef Exception", isOS_strlen("Undef Exception")+1, lr );
	while(1);
#else
	RESET_ENTRY p_reset_entry = (RESET_ENTRY)0x0;
	p_reset_entry();
#endif
}

/*
* Function Name:
*   PAbt_Handler_ISR
* Description:
*   ARM Undef handler ISR
* Parameters:
*   U32 lr: lr value
* Returns:
*   :
* Author				Date 
*  Jerry				2011-11-29   
* Note:
*    
*/
void PAbt_Handler_ISR( U32 lr )
{
#ifdef SYS_DEBUG_FLG
	IS_ASSERT_Execption( (U8*)"PAbt Exception", isOS_strlen("PAbt Exception")+1, lr );
	while(1);
#else
	RESET_ENTRY p_reset_entry = (RESET_ENTRY)0x0;
	p_reset_entry();
#endif
}

/*
* Function Name:
*   DAbt_Handler_ISR
* Description:
*   ARM Undef handler ISR
* Parameters:
*   U32 lr: lr value
* Returns:
*   :
* Author				Date 
*  Jerry				2011-11-29   
* Note:
*    
*/
void DAbt_Handler_ISR( U32 lr )
{
#ifdef SYS_DEBUG_FLG
	IS_ASSERT_Execption( (U8*)"DAbt Exception", isOS_strlen("DAbt Exception")+1, lr );
	while(1);
#else
	RESET_ENTRY p_reset_entry = (RESET_ENTRY)0x0;
	p_reset_entry();
#endif
}

